package com.palm.core.anno.impl;

import com.palm.core.anno.Auth;
import com.palm.core.util.TokenUtil;
import com.palm.platform.Current;
import com.palm.platform.domain.UserInfo;
import org.noear.solon.core.handle.Context;
import org.noear.solon.core.handle.Handler;
import org.noear.solon.core.wrap.MethodWrap;

import java.util.Set;
import java.util.function.BiFunction;

public class AuthHandler implements Handler {
    private static BiFunction<String, String, UserInfo> userLoader;

    public static void setUserLoader(BiFunction<String, String, UserInfo> loader) {
        userLoader = loader;
    }

    @Override
    public void handle(Context ctx) throws Throwable {
        if (ctx.getHandled()) {
            return;
        }
        //如果当前流程中已经处理过就跳过，避免重复处理
        if (ctx.attr("@_authed", false)) {
            return;
        }
        MethodWrap mw = ctx.action().method();
        Auth auth = mw.getAnnotation(Auth.class);
        if (auth == null) {
            auth=ctx.action().bean().annotationGet(Auth.class);
            if(auth==null){
                return;
            }
        }
        //标记已经处理过
        ctx.attrSet("@_authed", true);
        if (!auth.login()) {
            return;
        }
        String userType = auth.userType();
        UserInfo userInfo = Current.user(userType);
        if (userInfo == null && userLoader != null) {
            String token = Current.getUserToken(userType);
            String userName = TokenUtil.getData(token);
            if (userName != null) {
                UserInfo temp = userLoader.apply(userType, userName);
                if (temp != null) {
                    if (TokenUtil.validate(token, userName, temp.getPassword())) {
                        userInfo = temp;
                        Current.login(userType, userInfo);
                    }
                }
            }
        }
        if (userInfo == null) {
            ctx.setHandled(true);
            ctx.status(401);
            return;
        }

        if(userInfo.isSuper()){//超级用户有全部权限
            logAccess(userInfo,ctx);
            return;
        }
        String[] roles = auth.role();
        Set<String> userRoles = userInfo.getRoles();
        boolean hasRole = roles.length==0;
        for (String role : roles) {
            if (userRoles.contains(role)) {
                hasRole = true;
                break;
            }
        }
        if (!hasRole) {
            ctx.setHandled(true);
            ctx.status(403);
            return;
        }
        String[] permissions = auth.value();
        Set<String> userPermissions = userInfo.getPermissions();
        boolean hasPermission = permissions.length==0;
        for (String per : permissions) {
            if (userPermissions.contains(per)) {
                hasPermission = true;
                break;
            }
        }
        if (!hasPermission) {
            ctx.setHandled(true);
            ctx.status(403);
            return;
        }
        logAccess(userInfo,ctx);
    }
    private void logAccess(UserInfo userInfo,Context ctx){
        if("GET".equals(ctx.method())){
            return;
        }
        System.out.println(userInfo.getUsername()+" "+ctx.method()+ " "+ctx.path());
    }
}
